package br.ufrn.dimap.ase.squid.metrics.actions;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;

import br.ufrn.dimap.ase.squid.core.models.squidmodel.Mapping;
import br.ufrn.dimap.ase.squid.metrics.AbstractMetrics;
import br.ufrn.dimap.ase.squid.metrics.views.tree.model.InfoNode;
import br.ufrn.dimap.ase.squid.metrics.views.tree.model.Resultado;
import br.ufrn.dimap.ase.squid.metrics.visitors.VisitorMetricTamanho;


/**
 * Our sample action implements workbench action delegate.
 * The action proxy will be created by the workbench and
 * shown in the UI. When the user tries to use the action,
 * this delegate will be created and execution will be 
 * delegated to it.
 * @see IWorkbenchWindowActionDelegate
 */
public class TamanhoMetricsAction extends AbstractMetrics implements IWorkbenchWindowActionDelegate, IRunableMetrics {
	private IWorkbenchWindow window;
	/**
	 * The constructor.
	 */
	public TamanhoMetricsAction() {
	}

	@Override
	public void runMetrics() {
		VisitorMetricTamanho visitorMetricTamanho = new VisitorMetricTamanho(project, mapping, null);
		visitorMetricTamanho.visit();
	}

	@Override
	public void runMetrics(String feature) {
		VisitorMetricTamanho visitorMetricTamanho = new VisitorMetricTamanho(project, mapping, feature);
		visitorMetricTamanho.visit();
		
		// Colocando dados da LPS
		String loc = String.format("LOC: %d", visitorMetricTamanho.getLoc() );
		ArrayList<InfoNode> infos = new ArrayList<InfoNode>();
		infos.add(new InfoNode(loc));
		
		Set<String> keys = visitorMetricTamanho.getExplorador().getMapping().keySet();
		List<String> pacotes = new ArrayList<String>();
		int nClasses = 0;
		for(String key : keys) {
			List<File> files = visitorMetricTamanho.getExplorador().getMapping().get(key);
			nClasses += files.size();
			
			for(File file : files) {
				boolean add = true;
				for(String pacote : pacotes) {
					if(getPacote(file.getPath()).equalsIgnoreCase(pacote))
						add = false;
				}
				if(add)
					pacotes.add(getPacote( file.getPath()) );
			}
		}
		
		String nop = String.format("NOP: %d", pacotes.size() );
		String noc = String.format("NOC: %d", nClasses );
		infos.add(new InfoNode(nop));
		infos.add(new InfoNode(noc));
		// Fim colocando dados da LPS
		
		Resultado rLoc = new Resultado("Dados do tamanho da LPS", infos);
		Resultado rNoc = getResultadoClasses(visitorMetricTamanho, feature);
		Resultado rNop = getResultadoPacotes(visitorMetricTamanho, feature);
		String lof = String.format("LOF: %d", visitorMetricTamanho.getLocFeature());
		Resultado rLof = new Resultado(lof, new ArrayList<InfoNode>());
		
		addResultados(rLoc, rNoc, rNop, rLof);
		
		result = visitorMetricTamanho.toString();
	}
	
	/**
	 * Cria o Resultado de NOP
	 * 
	 * @param visitorMetricTamanho
	 * @param feature
	 * @return
	 */
	private Resultado getResultadoPacotes(VisitorMetricTamanho visitorMetricTamanho, String feature) {
		List<InfoNode> infosNop = new ArrayList<InfoNode>();

		List<String> pacotes = visitorMetricTamanho.getMappingPacotes().get(feature);
		for (String pacote : pacotes) {
			infosNop.add( 
					new InfoNode(pacote)
				);
		}
		return new Resultado("NOP: " + infosNop.size(), infosNop);
	}
	
	/**
	 * Cria o Resultado de NOC
	 * 	todas as classes anotadas completamente anotadas, para um feature
	 * 
	 * @param visitorMetricTamanho
	 * @param feature
	 * @return
	 */
	private Resultado getResultadoClasses(VisitorMetricTamanho visitorMetricTamanho, String feature) {
		List<InfoNode> infosNoc = new ArrayList<InfoNode>();

		List<Mapping> classes = visitorMetricTamanho.getMappingClasses().get(feature);
		for (Mapping mapping : classes) {
			String info = mapping.getName();
			if(info.contains(".java"))
				info = info.substring(0, mapping.getName().indexOf(".java"));
			
			infosNoc.add( new InfoNode(info) );
		}
		return new Resultado("NOC: " + infosNoc.size(), infosNoc);
	}
	
	/**
	 * Adiciona os resultados na variavel
	 * 
	 * @param resultados
	 */
	private void addResultados(Resultado... resultados) {
		this.resultados = new Resultado[resultados.length];
		
		for(int i = 0; i < resultados.length; i++) {
			this.resultados[i] = resultados[i];
		}
	}

	/**
	 * The action has been activated. The argument of the
	 * method represents the 'real' action sitting
	 * in the workbench UI.
	 * @see IWorkbenchWindowActionDelegate#run
	 */
	public void run(IAction action) {
		super.run();
	}

	/**
	 * Selection in the workbench has been changed. We 
	 * can change the state of the 'real' action here
	 * if we want, but this can only happen after 
	 * the delegate has been created.
	 * @see IWorkbenchWindowActionDelegate#selectionChanged
	 */
	public void selectionChanged(IAction action, ISelection selection) {
	}

	/**
	 * We can use this method to dispose of any system
	 * resources we previously allocated.
	 * @see IWorkbenchWindowActionDelegate#dispose
	 */
	public void dispose() {
	}

	/**
	 * We will cache window object in order to
	 * be able to provide parent shell for the message dialog.
	 * @see IWorkbenchWindowActionDelegate#init
	 */
	public void init(IWorkbenchWindow window) {
		this.window = window;
	}

	@Override
	public Map<String, List<Mapping>> getMappings() {
		return this.mapping;
	}
	
}